package com.xiaoshuidi.cloud.module.iot.service.impl.thirdPartImpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.AmmeterInfoResModel;
import com.xiaoshuidi.cloud.module.iot.api.device.vo.WaterMeterCommonResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.DeviceGetDailyPowerResModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.OperateThirdDeviceResponseModel;
import com.xiaoshuidi.cloud.module.iot.controller.admin.doorlock.vo.PullThirdDeviceRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenRequestModel;
import com.xiaoshuidi.cloud.module.iot.dal.model.AccessTokenResponseModel;
import com.xiaoshuidi.cloud.module.iot.dal.pojo.TbDeviceDo;
import com.xiaoshuidi.cloud.module.iot.dal.repository.DeviceRepository;
import com.xiaoshuidi.cloud.module.iot.enums.BrandEnum;
import com.xiaoshuidi.cloud.module.iot.enums.DeviceTypeEnum;
import com.xiaoshuidi.cloud.module.iot.enums.LuoSaiDevTypeEnum;
import com.xiaoshuidi.cloud.module.iot.service.AbstractThirdInstanceService;
import com.xiaoshuidi.cloud.module.iot.uitils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 罗赛对接
 */
@Service("luoSaiInstanceServiceImpl")
public class LuoSaiInstanceServiceImpl extends AbstractThirdInstanceService {

    private final static Logger LOGGER = LoggerFactory.getLogger(LuoSaiInstanceServiceImpl.class);

    //罗赛获取访问凭证
    @Value("${luosai.access_token.url}")
    private String luosaiAccessTokenUrl;
    //罗赛获取电表信息
    @Value("${luosai.getAmmeterInfo.url}")
    private String luosaiAmmeterInfo;
    @Value("${luosai.getWatermeterInfo.url}")
    private String watermeterInfoUrl;
    @Value("${luosai.getDeviceList.url}")
    private String luosaiDeviceListUrl;
    @Autowired
    private DeviceRepository deviceDataAccess;

    private final static String SUCCESS_FLAG = "success";

    @Override
    public String getBrand() {
       return BrandEnum.LUOSAI.getBrand();
    }

    @Override
    public AccessTokenResponseModel getAccessToken(AccessTokenRequestModel accessTokenRequestModel) throws Exception {
        AccessTokenResponseModel accessTokenResponseModel = new AccessTokenResponseModel();
        JSONObject bodyParam = new JSONObject();
        // 客户端ID
        bodyParam.put("rsId", accessTokenRequestModel.getAppId());
        // 客户端密码
        bodyParam.put("rsKey", accessTokenRequestModel.getAppKey());
        // 授权类型固定值：client_credentials
        bodyParam.put("grant_type", "client_credentials");
        LOGGER.info("罗赛获取access_token，请求url:{},请求参数:{}", luosaiAccessTokenUrl, bodyParam.toString());
        String result = HttpRequest.post(luosaiAccessTokenUrl).body(JSONUtil.toJsonStr(bodyParam))
                .header("Content-Type", "application/json").execute().body();
        LOGGER.info("罗赛获取access_token,返回结果:{}", result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject resultJsonObject = JSONObject.parseObject(result);
            accessTokenResponseModel = new AccessTokenResponseModel();
            if (SUCCESS_FLAG.equals(resultJsonObject.getString("flag"))) {
                // 罗赛访问凭证
                String access_token = resultJsonObject.getString("data");
                // 罗赛返回的令牌生命周期(秒) 固定5min
                accessTokenResponseModel.setAccessToken(access_token);
                // 设置罗赛访问凭证失效时间，比第三方少1分钟，也就是4分钟
                accessTokenResponseModel.setExpireTime(240);
            }
        }
        // 第三方业务返回逻辑处理,返回获取的token
        return accessTokenResponseModel;
    }

    @Override
    public List<TbDeviceDo> getDevice(PullThirdDeviceRequestModel pullThirdDeviceRequestModel) throws Exception {
        List<TbDeviceDo> tbDeviceDos = new ArrayList<>();
        String accessToken = pullThirdDeviceRequestModel.getAccessToken();
        List<TbDeviceDo> existDevices = deviceDataAccess.getDeviceListByOneApiNo(pullThirdDeviceRequestModel.getTbAccountDo().getApiNo());
        List<String> existDevicesUuid = existDevices.stream().map
                (TbDeviceDo::getDeviceThirdNo).collect(Collectors.toList());
        int pageNo = 1;
        int totalNo = 1;
        while (pageNo <= totalNo) {
            JSONObject bodyParam = new JSONObject();
            bodyParam.put("pageNo", pageNo);
            bodyParam.put("pageSize", 5000);//拉取5k条
            LOGGER.info("罗赛拉取设备，请求url:{},请求参数:{}", luosaiDeviceListUrl, bodyParam.toJSONString());
            String result = HttpRequest.post(luosaiDeviceListUrl).body(bodyParam.toJSONString())
                    .header("accessToken", accessToken)
                    .header("Content-Type", "application/json").execute().body();
            LOGGER.info("罗赛拉取设备，返回结果:{}", result);
            if (StrUtil.isNotBlank(result)) {
                JSONObject resultJsonObject = JSONObject.parseObject(result);
                if (SUCCESS_FLAG.equals(resultJsonObject.getString("flag"))) {
                    pageNo = pageNo + 1;
                    totalNo = resultJsonObject.getJSONObject("data").getInteger("total");
                    JSONArray devices = resultJsonObject.getJSONObject("data").getJSONArray("devices");
                    if (CollUtil.isNotEmpty(devices)) {
                        devices = devices.stream().filter(object ->
                                !existDevicesUuid.contains(((JSONObject) object).getString("deviceNumber"))).collect(Collectors.toCollection(JSONArray::new));
                        if (CollUtil.isNotEmpty(devices)) {
                            for (Iterator<Object> deviceIterator = devices.iterator(); deviceIterator.hasNext(); ) {
                                JSONObject deviceInfo = (JSONObject) deviceIterator.next();
                                // 水表读数，水表类型有效
                                String t = deviceInfo.getString("T");
                                // 电表读数，电表类型有效
                                String wpp = deviceInfo.getString("WPP");

                                TbDeviceDo tbDeviceDo = new TbDeviceDo();
                                // 表类型，10：电，20：水
                                String type = deviceInfo.getString("code");
                                // 设备序号
                                String deviceNumber = deviceInfo.getString("deviceNumber");
                                // 设备名称
                                String deviceName = deviceInfo.getString("deviceName");
                                // 设备状态，0：正常，-1：离线
                                Integer onoff = Optional.ofNullable(deviceInfo.getInteger("state")).orElse(-1);
                                // 状态，0：拉闸，1：合闸
                                Integer power = Optional.ofNullable(deviceInfo.getInteger("STU")).orElse(0);
                                tbDeviceDo.setDeviceThirdNo(deviceNumber);
                                tbDeviceDo.setDeviceName(deviceName);
                                tbDeviceDo.setDeviceModel("LS_".concat(type));
                                tbDeviceDo.setReportTime(LocalDateTime.now());
                                tbDeviceDo.setOnlineStatus(onoff == 0 ? 1 : 0);
                                tbDeviceDo.setPowerStatus(power == 1 ? 1 : 0);
                                if (LuoSaiDevTypeEnum.WATER.getCode().equals(type)) {//水
                                    tbDeviceDo.setDeviceType(DeviceTypeEnum.COLD_WATERMETE_TYPE_ENUM.getCode());
                                } else if (LuoSaiDevTypeEnum.AMMETER.getCode().equals(type)) {//电
                                    tbDeviceDo.setDeviceType(DeviceTypeEnum.AMMETER.getCode());
                                } else {
                                    continue;
                                }
                                tbDeviceDos.add(tbDeviceDo);
                            }
                        }
                    }
                } else {
                    String msg = pageNo > 1 ? "调用三方接口,拉取设备部分失败" : "调取三方接口，拉取设备全部失败";
                    throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), msg);
                }
            }
        }
        return tbDeviceDos;
    }

    @Override
    public List<TbDeviceDo> initializeDeviceInfo(List<TbDeviceDo> thirdDeviceList, PullThirdDeviceRequestModel pullThirdDeviceRequestModel) {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel addDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel getDynamicDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public AmmeterInfoResModel refreshAmmeterInfo(TbDeviceDo tbDeviceDo, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        AmmeterInfoResModel ammeterInfoResModel = new AmmeterInfoResModel();
        JSONObject data = this.getRespDataFromLuoSai(operateThirdDeviceRequestModel.getAccessToken(), tbDeviceDo.getDeviceThirdNo(), false);
        if (data != null) {
            /**
             * ├─ code	string	必须		表类型，10：电，20：水
             * ├─ WPP	string	非必须		电表读数，电表类型有效
             * ├─ STU	string	非必须		状态，0：拉闸，1：合闸
             * ├─ state	string	非必须		设备状态，0：正常，-1：离线
             * ├─ deviceName	string	必须		设备名称
             * ├─ deviceNumber	string	必须		设备序号
             */
            String state = data.getString("state");
            String stu = data.getString("STU");
            Double wpp = data.getDouble("WPP");
            String time = data.getString("time");
            Date reportTime = StringUtils.isBlank(time) ? new Date() : DateUtils.parseDateInCST(time);
            ammeterInfoResModel.setOnlineStatus("0".equals(state) ? 1 : 0);
            ammeterInfoResModel.setPowerStatus("1".equals(stu) ? 1 : 0);
            ammeterInfoResModel.setReportTime(reportTime);// 罗赛会返回一个抄表时间
            ammeterInfoResModel.setCurrentReading(wpp);
        }
        return ammeterInfoResModel;
    }

    private JSONObject getRespDataFromLuoSai(String accessToken, String deviceThirdNo, boolean isWater) {
        JSONObject bodyParam = new JSONObject();
        bodyParam.put("deviceNumber", deviceThirdNo); // 第三方设备ID
        String deviceType = isWater ? "水表" : "电表";
        String url = isWater ? watermeterInfoUrl : luosaiAmmeterInfo;
        LOGGER.info("罗赛获取{}基本信息，请求url:{},请求参数:{}", deviceType, url, bodyParam.toJSONString());
        String result = HttpRequest.post(url).body(JSONUtil.toJsonStr(bodyParam))
                .header("Content-Type", "application/json")
                .header("accessToken", accessToken).execute().body();
        LOGGER.info("罗赛获取基本信息，返回结果:{}", deviceType, result);
        if (StringUtils.isNotBlank(result)) {
            JSONObject resultJsonObject = JSONObject.parseObject(result);
            String code = resultJsonObject.getString("code");
            if (SUCCESS_FLAG.equals(resultJsonObject.getString("flag"))) {
                return resultJsonObject.getJSONObject("data");
            }
        }
        return null;
    }

    @Override
    public List<DeviceGetDailyPowerResModel> getDailyPower(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel updateDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel frozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel unfrozenDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchAmmeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel deleteDoorLockPassword(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public WaterMeterCommonResponseModel refreshWatermeterInfo(WaterMeterCommonResponseModel waterMeterCommonResponseModel, OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        waterMeterCommonResponseModel.setOperateResult(false);
        JSONObject data = this.getRespDataFromLuoSai(operateThirdDeviceRequestModel.getAccessToken(), waterMeterCommonResponseModel.getDeviceThirdNo(), true);
        if (data != null) {
            /**
             * ├─ code	string	必须		表类型，10：电，20：水
             * ├─ WPP	string	非必须		电表读数，电表类型有效
             * ├─ STU	string	非必须		状态，0：拉闸，1：合闸
             * ├─ state	string	非必须		设备状态，0：正常，-1：离线
             * ├─ deviceName	string	必须		设备名称
             * ├─ deviceNumber	string	必须		设备序号
             */
            String state = data.getString("state");
            String stu = data.getString("STU");
            Double wpp = data.getDouble("WPP");
            String time = data.getString("time");
            Date reportTime = StringUtils.isBlank(time) ? new Date() : DateUtils.parseDateInCST(time);
            waterMeterCommonResponseModel.setOnlineStatus("0".equals(state) ? 1 : 0);
            waterMeterCommonResponseModel.setPowerStatus("1".equals(stu) ? 1 : 0);
            waterMeterCommonResponseModel.setReportTime(reportTime);// 罗赛会返回一个抄表时间
            waterMeterCommonResponseModel.setCurrentReading(wpp);
            waterMeterCommonResponseModel.setOperateResult(true);
        }
        return waterMeterCommonResponseModel;
    }

    @Override
    public OperateThirdDeviceResponseModel getDoorLockStatus(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel getOpenLockRecordes(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOff(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchHotWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }

    @Override
    public OperateThirdDeviceResponseModel switchColdWaterMeterOn(OperateThirdDeviceRequestModel operateThirdDeviceRequestModel) throws Exception {
        return null;
    }
}
